package com.skyline.energy.jdbc.impl;

import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import net.sf.cglib.core.ReflectUtils;

import com.skyline.common.reflection.MethodUtils;
import com.skyline.energy.jdbc.RowMapper;
import com.skyline.energy.utils.BeanAutoDetect;
import com.skyline.energy.utils.JdbcUtils;

/**
 * 支持自动类型映射的RowMapper
 * 
 * 
 * @author wuqh
 * 
 * @param <T>
 */
public class AutoDetectRowMapper<T> extends BeanAutoDetect implements RowMapper<T> {
	private final Map<String, Integer> columnIndex = new HashMap<String, Integer>();

	public AutoDetectRowMapper(Class<T> clazz) throws Exception {
		super(clazz);
	}

	@SuppressWarnings("unchecked")
	@Override
	public T mapRow(ResultSet rs, int rowNum) throws SQLException {
		T result = (T) ReflectUtils.newInstance(clazz);

		if (result == null) {
			return result;
		}

		initColumnName(rs);

		Set<String> columnNameSet = columnIndex.keySet();
		for (String property : columnNameSet) {
			Method writeMethod = writeMethods.get(property);
			Object object = getResultSetValue(rs, property);
			MethodUtils.invokeMethod(result, writeMethod, convert(object, property));
		}

		return result;
	}

	private void initColumnName(ResultSet rs) throws SQLException {
		if (columnIndex.isEmpty()) {
			synchronized (columnIndex) {
				if (columnIndex.isEmpty()) {
					ResultSetMetaData metaData = rs.getMetaData();
					int columnCount = metaData.getColumnCount();
					for (int i = 1; i <= columnCount; i++) {
						columnIndex.put(metaData.getColumnName(i), i);
					}
				}
			}
		}

	}

	private Object getResultSetValue(ResultSet rs, String columnName) throws SQLException {
		int index = columnIndex.get(columnName);
		return JdbcUtils.getResultSetValue(rs, index);
	}

	@Override
	public boolean isAllowAutoMapType(Class<?> clazz) {
		return isSimpleType(clazz) || isAllowNumber(clazz);
	}

}
